package scan

import (
	"database/sql"
	"errors"
	"fmt"
	"reflect"
	"time"
)

var dataErr = errors.New("bsql: data is not a pointer")
var ptrErr = errors.New("bsql: data is a nil pointer")
var noColumnsErr = errors.New("bsql: no column")

func Scan(rows *sql.Rows, data interface{}) error {
	if scanner := trySqlScanner(data); scanner != nil {
		fmt.Println("trySqlScanner")
		if rows.Next() {
			if err := rows.Scan(scanner); err != nil {
				return err
			}
		}
		return rows.Err()
	}

	ptr := reflect.ValueOf(data)
	if ptr.Kind() != reflect.Ptr {
		return dataErr
	}
	if ptr.IsNil() {
		return ptrErr
	}

	columns, err := rows.ColumnTypes()
	if err != nil {
		return err
	}
	if len(columns) == 0 {
		return noColumnsErr
	}

	target := ptr.Elem()
	switch target.Kind() {
	case reflect.Slice:
	default:
		if rows.Next() {
			if err = scanRow(rows, columns, target); err != nil {
				return err
			}
		}
	}

	return rows.Err()
}

func scanRow(rows *sql.Rows, columns []*sql.ColumnType, target reflect.Value) error {
	addr := target.Addr().Interface()
	if scanner := trySqlScanner(addr); scanner != nil {
		return rows.Scan(addr)
	}
	switch addr.(type) {
	case *time.Time:
		return rows.Scan(scannerOf(target,columns[0]))
	}
	switch target.Kind() {
	case reflect.Struct:
		// TODO scan to struct
		return scan2Struct(rows,target,columns)
	case reflect.Map:
		// TODO scan to map
		return nil
	default:
		if err := rows.Scan(scannerOf(target, columns[0])); err != nil {
			return err
		}
	}
	return nil
}

func scan2Struct(rows *sql.Rows, target reflect.Value, columns []*sql.ColumnType) error {
	//var scanners []interface{}
	//for _,column := range columns {
	//
	//}
	return nil
}

func trySqlScanner(ptr interface{}) sql.Scanner {
	if scanner, ok := ptr.(sql.Scanner); ok {
		//switch v := ptr.(type) {
		//
		//}
		return scanner
	}
	return nil
}
